home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / icmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-07  |  18.1 KB  |  693 lines

  1. /* 
  2.  * icmp.c --
  3.  *
  4.  *    Routines to handle the ICMP protocol, as specified in RFC 792 
  5.  *    "Internet Control Message Protocol" (Sept. 1981) and RFC 950 
  6.  *    "Internet Standard Subnetting Procedure" (Aug. 1985). 
  7.  *    Incoming packets are validated and an action is taken depending 
  8.  *    of the type of the packet. ICMP packets may be sent to a host 
  9.  *    to indicate errors with the ICMP_SendErrorMsg routine.
  10.  *
  11.  *    Based on 4.3BSD  @(#)ip_icmp.c 7.6 (Berkeley) 8/31/87
  12.  *
  13.  *     To do: handle
  14.  *     1) routing redirects.
  15.  *     2) source quench.
  16.  *
  17.  * Copyright 1987 Regents of the University of California
  18.  * All rights reserved.
  19.  * Permission to use, copy, modify, and distribute this
  20.  * software and its documentation for any purpose and without
  21.  * fee is hereby granted, provided that the above copyright
  22.  * notice appear in all copies.  The University of California
  23.  * makes no representations about the suitability of this
  24.  * software for any purpose.  It is provided "as is" without
  25.  * express or implied warranty.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/icmp.c,v 1.10 90/08/06 17:17:56 mendel Exp $ SPRITE (Berkeley)";
  30. #endif not lint
  31.  
  32.  
  33. #include "sprite.h"
  34. #include "ipServer.h"
  35. #include "stat.h"
  36. #include "ip.h"
  37. #include "icmp.h"
  38. #include "route.h"
  39. #include "socket.h"
  40. #include "raw.h"
  41.  
  42. static void    Input();
  43. static void    ReturnToSender();
  44. static void    SwapAddresses();
  45.  
  46. /*
  47.  * Names of all ICMP types and names for the UNREACHABLE and REDIRECT codes.
  48.  */
  49. static char     *typeNames[] = {
  50.     "ECHO_REPLY",
  51.     "type 1 - unused",
  52.     "type 2 - unused",
  53.     "UNREACHABLE",
  54.     "SOURCE_QUENCH",
  55.     "REDIRECT",
  56.     "type 6 - unused",
  57.     "type 7 - unused",
  58.     "ECHO",
  59.     "type 9 - unused",
  60.     "type 10 - unused",
  61.     "TIME_EXCEED",
  62.     "PARAM_PROB",
  63.     "TIMESTAMP",
  64.     "TIMESTAMP_REPLY",
  65.     "INFO_REQ",
  66.     "INFO_REPLY",
  67.     "MASK_REQ",
  68.     "MASK_REPLY",
  69. };
  70.  
  71. static char *unreachCodeNames[] = {
  72.     "bad net", 
  73.     "bad host", 
  74.     "bad protocol", 
  75.     "bad port", 
  76.     "need to frag", 
  77.     "src route failed",
  78. };
  79.  
  80. static char *redirectCodeNames[] = {
  81.     "network",
  82.     "host",
  83.     "type of service and network",
  84.     "type of service and host",
  85. };
  86.  
  87.  
  88. /*
  89.  *----------------------------------------------------------------------
  90.  *
  91.  * ICMP_Init --
  92.  *
  93.  *    Establishes the callback routine to handle incoming ICMP packets.
  94.  *
  95.  * Results:
  96.  *    None.
  97.  *
  98.  * Side effects:
  99.  *    A routine will be called whenever a ICMP packet arrives.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103.  
  104. void
  105. ICMP_Init()
  106. {
  107.     IP_SetProtocolHandler(NET_IP_PROTOCOL_ICMP, Input);
  108. }
  109.  
  110.  
  111. /*
  112.  *----------------------------------------------------------------------
  113.  *
  114.  * Input --
  115.  *
  116.  *    This routine is called whenever an ICMP packet arrives.
  117.  *    Once the packet is validated by checking that the length, checksum
  118.  *    and the type are proper, the type value is used to decide what action 
  119.  *    to take. There are 2 kinds of ICMP types:
  120.  *    1) informational: echo, timestamp, mask and address info requests and
  121.  *        replies.
  122.  *    2) error: unreachable host, net, or port; bad options format;
  123.  *         route redirect, source quench, etc.
  124.  *    The informational requests are handled in a separate routine. 
  125.  *    Informational replies are passed to raw socket handler. The 
  126.  *    error types are handled here and they indicate that there was a 
  127.  *    problem with a packet we have sent.
  128.  *
  129.  * Results:
  130.  *    None.
  131.  *
  132.  * Side effects:
  133.  *    Info request packets are returned to the sender. Error packets pass
  134.  *    information to higher-level protocols. Replies pass to the raw 
  135.  *    socket layer.
  136.  *
  137.  *----------------------------------------------------------------------
  138.  */
  139.  
  140. /*ARGSUSED*/
  141. static void
  142. Input(netID, packetPtr)
  143.     Rte_NetID  netID;        /* ID of the network the packet arrived on. */
  144.     IPS_Packet    *packetPtr;    /* Packet descriptor. */
  145. {
  146.     register Net_ICMPPacket    *icmpPtr;
  147.     register Net_IPHeader    *ipPtr;
  148.     int                dataLen;
  149.     unsigned char        type;
  150.     ReturnStatus        status;
  151.  
  152.     stats.icmp.total++;
  153.  
  154.     /*
  155.      * Determine the start of the ICMP part of the packet. Fill in the
  156.      * packet descriptor in case we need to ship the packet back to the 
  157.      * sender.
  158.      */
  159.  
  160.     ipPtr   = packetPtr->ipPtr;
  161.     icmpPtr = (Net_ICMPPacket *) ((Address)ipPtr + (ipPtr->headerLen * 4));
  162.     packetPtr->data = (Address) icmpPtr;
  163.  
  164.     /*
  165.      * We assume the ipPtr->totalLen is in host byte order.
  166.      */
  167.     dataLen = ipPtr->totalLen - (ipPtr->headerLen * 4);
  168.     packetPtr->dataLen = dataLen;
  169.     packetPtr->ipLen = ipPtr->headerLen * 4;
  170.     packetPtr->hdrLen = 0;
  171.  
  172.     /*
  173.      * Make sure the packet has the proper length.
  174.      */
  175.     if (dataLen < NET_ICMP_MIN_LEN) {
  176.     stats.icmp.shortLen++;
  177.     free(packetPtr->base);
  178.     return;
  179.     }
  180.  
  181.     /*
  182.      * See if the checksum is OK. Since the checksum value in the packet is 
  183.      * not zeroed when calculating the value here, the result should be 0
  184.      * if the packet was not garbled.
  185.      */
  186.     if (Net_InetChecksum(dataLen, (Address) icmpPtr) != 0) {
  187.     stats.icmp.badChecksum++;
  188.     free(packetPtr->base);
  189.     return;
  190.     }
  191.  
  192.     /*
  193.      * Make sure the type is in range before incrementing the counter. 
  194.      * A unknown type is not rejected in order to give the packet
  195.      * to the raw socket layer.  This allows development of new ICMP types.
  196.      */
  197.  
  198.     type = icmpPtr->header.type; 
  199.  
  200.     if  (type > NET_ICMP_MAX_TYPE) {
  201.     stats.icmp.badType++;
  202.     } else {
  203.     stats.icmp.inHistogram[type]++;
  204.     }
  205.  
  206.  
  207.     if (ips_Debug) {
  208.     (void) fprintf(stderr, "ICMP Input: <%x>  <---  <%x>  %s", 
  209.         Net_NetToHostInt(ipPtr->dest), 
  210.         Net_NetToHostInt(ipPtr->source), 
  211.         typeNames[type]);
  212.     if (type ==  NET_ICMP_UNREACHABLE) {
  213.         (void) fprintf(stderr, " -- %s\n", unreachCodeNames[icmpPtr->header.code]);
  214.     } else {
  215.         (void) fprintf(stderr, " -- %d\n", icmpPtr->header.code);
  216.     }
  217.     }
  218.  
  219.     switch (type) {
  220.  
  221.     /*
  222.      * The following types involve the return of some information
  223.      * to the sender. Users don't ever get to see these packets.
  224.      */
  225.  
  226.     case NET_ICMP_ECHO:
  227.     case NET_ICMP_TIMESTAMP:
  228.     case NET_ICMP_INFO_REQ:
  229.     case NET_ICMP_MASK_REQ:
  230.         ReturnToSender(netID, type, dataLen, icmpPtr, packetPtr);
  231.         break;
  232.  
  233.  
  234.  
  235.     /*
  236.      * The following types are feedback about problems with packets
  237.      * that have been sent out. The higher-level protocol that sent
  238.      * the packet needs to be told about the problem.
  239.      */
  240.  
  241.     case NET_ICMP_UNREACHABLE:
  242.         switch (icmpPtr->header.code) {
  243.         case NET_ICMP_UNREACH_NET:
  244.             status = NET_UNREACHABLE_NET;
  245.             break;
  246.  
  247.         case NET_ICMP_UNREACH_HOST:
  248.             status = NET_UNREACHABLE_HOST;
  249.             break;
  250.  
  251.         case NET_ICMP_UNREACH_PROTOCOL:
  252.             status = NET_CONNECT_REFUSED;
  253.             break;
  254.  
  255.         case NET_ICMP_UNREACH_PORT:
  256. #ifdef    REAL_RAW
  257.             if(ips_Debug)
  258.             (void) fprintf(stderr,
  259.                 "ICMP Input: <%x>  <---  <%x> %s -- bad port\n", 
  260.                 Net_NetToHostInt(ipPtr->dest), 
  261.                 Net_NetToHostInt(ipPtr->source), 
  262.                 typeNames[type]);
  263.             Raw_Input(NET_IP_PROTOCOL_ICMP, ipPtr->source, ipPtr->dest, 
  264.                 packetPtr);
  265. #endif    REAL_RAW
  266.             status = NET_CONNECT_REFUSED;
  267.             break;
  268.  
  269.         case NET_ICMP_UNREACH_NEED_FRAG:
  270.             status = FS_BUFFER_TOO_BIG;
  271.             break;
  272.  
  273.         case NET_ICMP_UNREACH_SRC_ROUTE:
  274.             status = NET_UNREACHABLE_HOST;
  275.             break;
  276.  
  277.         default:
  278.             stats.icmp.badCode++;
  279.             status = SUCCESS;
  280.             break;
  281.         }
  282.         if (status != SUCCESS) {
  283.         /*
  284.          * Pass the protocol, destination and the first 64 bits
  285.          * of the data to the error handler.
  286.          */
  287.         int hdrLen = icmpPtr->data.unreach.ipHeader.headerLen * 4;
  288.  
  289.         Sock_ReturnError(status,
  290.             (int)icmpPtr->data.unreach.ipHeader.protocol, 
  291.             icmpPtr->data.unreach.ipHeader.dest,
  292.             (Address) ((Address) &icmpPtr->data.unreach.ipHeader) + 
  293.                     hdrLen);
  294.         }
  295.         break;
  296.  
  297.     /*
  298.      * A source quench packet is sent by a gateway if it ran out of buffers
  299.      * or by a host if we have sent many packets too quickly. We need
  300.      * to cut back on the rate of delivery.
  301.      */
  302.     case NET_ICMP_SOURCE_QUENCH:
  303.         /* To do: pass info to offending protocol layer. */
  304.         break;
  305.  
  306.     /*
  307.      * A gateway has informed us of a shorter path to a destination.
  308.      */
  309.     case NET_ICMP_REDIRECT:
  310.         if (icmpPtr->header.code > NET_ICMP_REDIRECT_TOS_NET) {
  311.         stats.icmp.badCode++;
  312.         } else {
  313.         /*
  314.          * To do: give the information to the routing handler.
  315.          */
  316.         if (icmpPtr->header.code == NET_ICMP_REDIRECT_HOST) {
  317.             Rte_UpdateRoute(
  318.                 Net_NetToHostInt(icmpPtr->data.redirect.ipHeader.dest),
  319.                     icmpPtr->data.redirect.gatewayAddr);
  320.         }
  321.         if (ips_Debug) {
  322.             (void) fprintf(stderr, 
  323.             "ICMP Redirect: %s  new=<%x> old=<%x>\n",
  324.             redirectCodeNames[icmpPtr->header.code],
  325.             icmpPtr->data.redirect.gatewayAddr,
  326.             icmpPtr->data.redirect.ipHeader.dest);
  327.         }
  328.         }
  329.         break;
  330.  
  331. #ifndef    REAL_RAW
  332.     /*
  333.      * The Time Exceeded type is sent when a gateway has found that 
  334.      * a packet's time to live value is 0 or when a host trying to 
  335.      * reassemble a fragmented packet has not received all of the 
  336.      * fragments within a certain amount of time.
  337.      */
  338.     case NET_ICMP_TIME_EXCEED:
  339.         /*
  340.          * This message type is ignored.
  341.          */
  342.         if (icmpPtr->header.code > NET_ICMP_TIME_EXCEED_REASS) {
  343.         stats.icmp.badCode++;
  344.         }
  345.         break;
  346. #endif    REAL_RAW
  347.  
  348.     /*
  349.      * NET_ICMP_PARAM_PROB means there was a problem in the header 
  350.      * parameters of a packet we sent. The packet had to be discarded.
  351.      */
  352.     case NET_ICMP_PARAM_PROB: {
  353.         int hdrLen = icmpPtr->data.param.ipHeader.headerLen * 4;
  354.  
  355.         Sock_ReturnError((ReturnStatus) NET_BAD_OPTION, 
  356.                 (int)icmpPtr->data.param.ipHeader.protocol, 
  357.                 icmpPtr->data.param.ipHeader.dest,
  358.                 (Address)((Address) &icmpPtr->data.param.ipHeader) +
  359.                     hdrLen);
  360.         }
  361.         break;
  362.  
  363.  
  364.     /*
  365.      * The following types must be made available to the clients.
  366.      * Also give packets with unknown types to the clients in case
  367.      * they're using a new type we don't know about yet.
  368.      */
  369. #ifdef    REAL_RAW
  370.     case NET_ICMP_TIME_EXCEED:
  371.         if(ips_Debug)
  372.         (void) fprintf(stderr,
  373.             "ICMP Input: <%x>  <---  <%x> %s\n", 
  374.             Net_NetToHostInt(ipPtr->dest), 
  375.             Net_NetToHostInt(ipPtr->source), 
  376.             typeNames[type]);
  377. #endif    REAL_RAW
  378.     case NET_ICMP_ECHO_REPLY:
  379.     case NET_ICMP_TIMESTAMP_REPLY:
  380.     case NET_ICMP_INFO_REPLY:
  381.     case NET_ICMP_MASK_REPLY:
  382.     default:
  383.         Raw_Input(NET_IP_PROTOCOL_ICMP, ipPtr->source, ipPtr->dest, 
  384.             packetPtr);
  385.     }
  386.     free(packetPtr->base);
  387. }
  388.  
  389.  
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * ReturnToSender --
  394.  *
  395.  *    Handles ICMP echo, timestamp, info request and mask request packets.
  396.  *    The packet is processed and then returned to the sender.
  397.  *
  398.  * Results:
  399.  *    None.
  400.  *
  401.  * Side effects:
  402.  *    A packet is returned to the sender after a bit of processing.
  403.  *
  404.  *----------------------------------------------------------------------
  405.  */
  406.  
  407. static void
  408. ReturnToSender(netID, type, dataLen, icmpPtr, packetPtr)
  409.     Rte_NetID              netID;        /* ID of the network the 
  410.                          * packet came arrived on. */
  411.     unsigned char        type;        /* ICMP type. */
  412.     int                dataLen;    /* Size in bytes of the data
  413.                          * in the packet. */
  414.     register Net_ICMPPacket    *icmpPtr;    /* Ptr to ICMP packet. */
  415.     IPS_Packet    *packetPtr;            /* Packet descriptor. */
  416. {
  417.     register Net_IPHeader *ipHdrPtr = packetPtr->ipPtr;
  418.  
  419.     switch (type) {
  420.  
  421.     /*
  422.      * ECHO: just return the packet as is (but change the type to reply).
  423.      */
  424.     case NET_ICMP_ECHO:
  425.         icmpPtr->header.type = NET_ICMP_ECHO_REPLY;
  426.         break;
  427.  
  428.  
  429.     /*
  430.      * TIMESTAMP: set the times.
  431.      */
  432.     case NET_ICMP_TIMESTAMP:
  433.         if (dataLen < sizeof(Net_ICMPHeader) + sizeof(Net_ICMPDataTime)) {
  434.         stats.icmp.shortLen++;
  435.         return;
  436.         }
  437.         icmpPtr->header.type = NET_ICMP_TIMESTAMP_REPLY;
  438.  
  439.         /*
  440.          * The timestamp should record when we received the packet and
  441.          * when it was sent out.  Just set the transmit time
  442.          * to the receive time -- it'll probably be close enough to
  443.          * the real transmit time...
  444.          */
  445.         icmpPtr->data.timeStamp.recvTime = 
  446.                 Net_HostToNetInt(IPS_GetTimestamp());
  447.         icmpPtr->data.timeStamp.transmitTime = 
  448.                     icmpPtr->data.timeStamp.recvTime;
  449.         break;
  450.  
  451.  
  452.  
  453.     /*
  454.      * INFO: adjust the source address if it was a broadcast.
  455.      */
  456.     case NET_ICMP_INFO_REQ:
  457.         icmpPtr->header.type = NET_ICMP_INFO_REPLY;
  458.         if (Net_InetAddrNetNum(ipHdrPtr->source) == 0) {
  459.         /*
  460.          * Broadcast to this network: 
  461.          */
  462.         ipHdrPtr->source = Net_MakeInetAddr(Rte_GetNetNum(netID), 
  463.                 Net_InetAddrHostNum(ipHdrPtr->source));
  464.         }
  465.         break;
  466.  
  467.  
  468.  
  469.     /*
  470.      * MASK: return the subnet mask for the network the packet came in on.
  471.      */
  472.     case NET_ICMP_MASK_REQ:
  473.         if (dataLen < sizeof(Net_ICMPHeader) + sizeof(Net_ICMPDataMask)) {
  474.         stats.icmp.shortLen++;
  475.         return;
  476.         }
  477.         icmpPtr->header.type = NET_ICMP_MASK_REPLY;
  478.         icmpPtr->data.mask.addrMask = 
  479.                 Net_HostToNetInt(Rte_GetSubnetMask(netID));
  480.  
  481.         /*
  482.          * RFC950 ("Internet Standard Subnetting Procedure") says on p.10 
  483.          * that if the source address is 0, then the destination address 
  484.          * for the reply should be a broadcast address. Since the source 
  485.          * and dest. will swapped below, set the source here.
  486.          */
  487.         if (ipHdrPtr->source == 0) {
  488.         ipHdrPtr->source = Rte_GetBroadcastAddr(netID);
  489.         }
  490.         break;
  491.  
  492.  
  493.  
  494.     default:
  495.         panic("ReturnToSender: bad type %d\n", type);
  496.         return;
  497.         break;
  498.     }
  499.  
  500.  
  501.     /*
  502.      * Swap the source and destination addresses since we're sending 
  503.      * the packet back.
  504.      */
  505.     SwapAddresses(ipHdrPtr);
  506.  
  507.     /*
  508.      * We have to recompute the checksum because of the changes made above.
  509.      */
  510.     icmpPtr->header.checksum = 0;
  511.     icmpPtr->header.checksum = Net_InetChecksum(dataLen, (Address) icmpPtr);
  512.     packetPtr->ipPtr->timeToLive = NET_IP_MAX_TTL;
  513.     (void) IP_Output(packetPtr, FALSE);
  514. }
  515.  
  516. /*
  517.  *----------------------------------------------------------------------
  518.  *
  519.  * ICMP_SendErrorMsg --
  520.  *
  521.  *    Sends an ICMP packet to the source of a bad IP packet.
  522.  *
  523.  * Results:
  524.  *    None.
  525.  *
  526.  * Side effects:
  527.  *    An ICMP error packet is sent to the offending host.
  528.  *
  529.  *----------------------------------------------------------------------
  530.  */
  531.  
  532. void
  533. ICMP_SendErrorMsg(ipHdrPtr, type, code)
  534.     Net_IPHeader    *ipHdrPtr;    /* Ptr to IP header for the packet. */
  535.     int            type;        /* ICMP type to return. */
  536.     int            code;        /* ICMP code to return. */
  537. {
  538.     Net_ICMPPacket    *icmpPtr;
  539.     IPS_Packet        packet;
  540.     int            ipHdrLen;
  541.     Net_InetAddress    dest;
  542.     int            srcRteLen;
  543.     Address        srcRoutePtr;
  544.     int            ipDataLen;
  545.     int            len;
  546.  
  547.     if (type > NET_ICMP_MAX_TYPE) {
  548.     panic("ICMP_SendErrorMsg: bad type: %d\n", type);
  549.     return;
  550.     }
  551.  
  552.     /*
  553.      * Only send an error if the packet is the first fragment.
  554.      */
  555.     if (ipHdrPtr->fragOffset != 0) {
  556.     return;
  557.     }
  558.  
  559.     ipHdrLen = ipHdrPtr->headerLen * 4;
  560.  
  561.     /*
  562.      * Don't send if the packet's protocol was ICMP and the error type is
  563.      * not a redirect and the packet's ICMP type was not an informational
  564.      * type.
  565.      */
  566.     if ((ipHdrPtr->protocol == NET_IP_PROTOCOL_ICMP) &&
  567.     (type != NET_ICMP_REDIRECT)) {
  568.  
  569.     switch (((Net_ICMPHeader *)(((Address) ipHdrPtr) + ipHdrLen))->type) {
  570.         case NET_ICMP_ECHO_REPLY:
  571.         case NET_ICMP_ECHO:
  572.         case NET_ICMP_TIMESTAMP:
  573.         case NET_ICMP_TIMESTAMP_REPLY:
  574.         case NET_ICMP_INFO_REQ:
  575.         case NET_ICMP_INFO_REPLY:
  576.         case NET_ICMP_MASK_REQ:
  577.         case NET_ICMP_MASK_REPLY:
  578.         break;
  579.  
  580.         default:
  581.         return;
  582.         break;
  583.     }
  584.     }
  585.  
  586.  
  587.     /*
  588.      * We need to format an ICMP packet that is composed of
  589.      *    1) an IP header: we use the header + source route options from the 
  590.      *     error packet, with the src and dest addresses swapped.
  591.      *  2) the ICMP header: we use the type and code arguments to this routine.
  592.      *    3) a type-dependent value (an integer).
  593.      *  4) the IP header of the error packet: this includes the basic
  594.      *        header and options.
  595.      *  5) the first 8 octets of data from the error packet.
  596.      *
  597.      * It is assumed that only error-type packets are sent, hence the
  598.      * use of the overlay to include the IP header and data.
  599.      */
  600.  
  601.     IPS_InitPacket(sizeof(Net_ICMPPacket), &packet);
  602.  
  603.     packet.data = packet.dbase + (packet.totalLen - sizeof(Net_ICMPPacket));
  604.     icmpPtr     = (Net_ICMPPacket *) packet.data;
  605.     
  606.     ipDataLen    = ipHdrPtr->totalLen - ipHdrLen;
  607.     len        = ipHdrLen + MIN(8, ipDataLen);
  608.     packet.dataLen = sizeof(Net_ICMPHeader) + sizeof(int) + len;
  609.  
  610.     bcopy( (Address) ipHdrPtr, 
  611.           (Address) &icmpPtr->data.overlay.ipHeader, len);
  612.  
  613.     if (type == NET_ICMP_REDIRECT) {
  614.     icmpPtr->data.redirect.gatewayAddr = 0;
  615.     } else {
  616.     icmpPtr->data.overlay.unused = 0;
  617.     }
  618.     if (type == NET_ICMP_PARAM_PROB) {
  619.     icmpPtr->data.param.paramOffset = code;
  620.     code = 0;
  621.     }
  622.     icmpPtr->header.type = type;
  623.     icmpPtr->header.code = code;
  624.     icmpPtr->header.checksum = 0;
  625.     icmpPtr->header.checksum = Net_InetChecksum(packet.dataLen, 
  626.                     (Address) icmpPtr);
  627.  
  628.     /*
  629.      * Now we format the IP header for the packet. Swap the src and dest
  630.      * addresses since we're returning the packet to the sender.  Include
  631.      * the source-route header options if they're present; other options
  632.      * in the header are not returned.
  633.      */
  634.  
  635.     SwapAddresses(ipHdrPtr);
  636.  
  637.     if (ipHdrLen > sizeof(Net_IPHeader)) {
  638.     srcRoutePtr = IP_GetSrcRoute(&srcRteLen, &dest);
  639.     }
  640.  
  641.     packet.ipLen = sizeof(Net_IPHeader) + srcRteLen;
  642.     packet.ipPtr = (Net_IPHeader *) ((Address) packet.data) - packet.ipLen;
  643.     *packet.ipPtr = *ipHdrPtr;
  644.     if (srcRteLen > 0) {
  645.     bcopy( srcRoutePtr, 
  646.         ((Address) (packet.ipPtr)) + sizeof(Net_IPHeader), srcRteLen);
  647.     free(srcRoutePtr);
  648.     packet.ipPtr->dest = dest;
  649.     }
  650.  
  651.     packet.ipPtr->headerLen = packet.ipLen / 4;
  652.     packet.ipPtr->totalLen = packet.ipLen + packet.dataLen;
  653.     packet.ipPtr->timeToLive = NET_IP_MAX_TTL;
  654.     packet.ipPtr->protocol = NET_IP_PROTOCOL_ICMP;
  655.     (void) IP_Output(&packet, TRUE);
  656.     free(packet.base);
  657. }
  658.  
  659.  
  660. /*
  661.  *----------------------------------------------------------------------
  662.  *
  663.  * SwapAddresses --
  664.  *
  665.  *    Swap the source and destination addresses of an IP header. If the
  666.  *    original destination/new source is a broadcast address, then
  667.  *    change it to our official IP address.
  668.  *
  669.  * Results:
  670.  *    None.
  671.  *
  672.  * Side effects:
  673.  *    The addresses in an IP header are changed.
  674.  *
  675.  *----------------------------------------------------------------------
  676.  */
  677.  
  678. static void
  679. SwapAddresses(ipPtr)
  680.     Net_IPHeader    *ipPtr;
  681. {
  682.     Net_InetAddress    temp;
  683.  
  684.     temp = ipPtr->dest;
  685.     ipPtr->dest = ipPtr->source;
  686.  
  687.     if (Rte_IsBroadcastAddr(temp)) {
  688.     ipPtr->source = Rte_GetOfficialAddr(FALSE);
  689.     } else {
  690.     ipPtr->source = temp;
  691.     }
  692. }
  693.